'''
用于采矿和建筑的建造工具系统
'''

from random import randint,randrange,random
from ursina import Entity,color,texture,Vec3
from numpy import floor



class Mining_system:

    def __init__(this,_subject,_axe,_camera,_subsets,_megasets):

        #创建了引用，以便在 buildTool()中使用
        this.subject = _subject
        this.axe = _axe
        this.camera = _camera

        #记录地形位置的字典包括缝隙
        this.tDic = {}
        this.buildTex = 'build_texture.png'
        this.cubeModel = 'moonCube.obj'
        this.builds = Entity(model=this.cubeModel,texture=this.buildTex)

        this.subsets = _subsets
        this.megasets = _megasets

        this.wireTex = 'wireframe.png'
        this.stoneTex = 'grass_mono.png'
        #构建工具实体
        this.bte = Entity(model='cube', texture=this.wireTex,scale=1.01)

        # 建造距离
        this.build_distance = 3
        #-1 is OFF,1 is ON
        this.buildMode = -1

        #新的模块   枚举构建工具显示区域方块颜色类型类，草块土壤石头宝石
        this.blockTypes = []
        # Stone - 0
        this.blockTypes.append(color.rgb(255, 255, 255))
        # Grass - 1
        this.blockTypes.append(color.rgb(0, 255, 0))
        # Soil - 2
        this.blockTypes.append(color.rgb(102, 51, 0))
        # Ruby - 3
        this.blockTypes.append(color.rgb(255, 0, 0))
        # Netherite - 4
        this.blockTypes.append(color.rgb(0, 0, 0))
        #当前模块
        this.blockType = 0  #I.e. stone.

    def input(this,key):
        # 鼠标滚轮滑动，调整建造模式预制体距离，更近or更远
        if key == 'scroll up':
            this.build_distance += 1
        if key == 'scroll down':
            this.build_distance -= 1

        if this.buildMode == 1 and key == 'right mouse up':
            this.build()
            #this.axe.position = Vec3(0.3, -0.5, 2.8)
        elif this.buildMode == 1 and key == 'left mouse up':
            this.mine()
            this.axe.shake(duration=0.3, magnitude=7,
                           direction=(-1, 1))
            #this.axe.position = Vec3(0.3, -0.5, 2.8)
        #else: this.axe.position = Vec3(2, 0, 2.8)
            # I.e. return axe to default position if not in build mode.

        #切换构建模式
        if key == 'f': this.buildMode *= -1


        if key == '1': this.blockType = 0
        if key == '2': this.blockType = 1
        if key == '3': this.blockType = 2
        if key == '4': this.blockType = 3
        if key == '5': this.blockType = 4


    #这是从主更新循环调用
    def buildTool(this):
        # 如果不处于创造模式，无法使用
        if this.buildMode == -1:
            this.bte.visible = False
            return
        else: this.bte.visible = True
        this.bte.position = round(this.subject.position + this.camera.forward * this.build_distance)
        # 按照提示放置方块
        this.bte.y += 2
        this.bte.y = round(this.bte.y)
        this.bte.x = round(this.bte.x)
        this.bte.z = round(this.bte.z)
        this.bte.color = this.blockTypes[this.blockType]

    def adjustShadeAndRotation(this,_block):
        from copy import copy
        # 改变形状为soil（blockTypes[2]）的
        _block.color = copy(this.blockTypes[2])
        # 调整这个色块的颜色
        shade = randrange(-16, 64) / 256
        _block.color[0] += shade
        _block.color[1] += shade
        _block.color[2] += shade

        #添加随机旋转
        _block.rotation_y = (90 * randint(0, 3))
        _block.rotation_z = (90 * randint(0, 3))
        _block.rotation_x = (90 * randint(0, 3))

    def mineSpawn(this):
        from copy import copy #复制颜色

        #在挖掘位置下生成一块
        if this.tDic.get('x' + str(this.bte.x) + 'y' + str(this.bte.y - 1) + 'z' + str(this.bte.z)) == None:
            # 记录字典中间隙的位置
            '''
            this.tDic['x' + str(this.bte.x) + 'y' + str(this.bte.y) + 'z' + str(this.bte.z)] = 'gap''
            '''
            # 现在需要生成一个新的立方体，如果这里没有立方体或间隙生成四个立方体造成多层次的感觉
            e = Entity(model=this.cubeModel, texture=this.buildTex)
            # 缩小方块与普通地形大小匹配
            e.scale *= 0.99999

            # 生成位置在mined之下
            e.position = this.bte.position
            e.y -= 1

            this.adjustShadeAndRotation(e)

            # 父类生成立方体去构建实体
            e.parent = this.builds
            # 记录在字典中新生成的块
            this.tDic['x' + str(this.bte.x) +
                      'y' + str(e.y) +
                      'z' + str(this.bte.z)] = 's'
            this.builds.combine()
        # 现在生成四面墙的方块，但要检测是否有地形，没有间隙，这个下面有没有地形
        x = this.bte.x
        y = this.bte.y
        z = this.bte.z
        pos1 = (x + 1, y, z)
        pos2 = (x - 1, y, z)
        pos3 = (x, y, z + 1)
        pos4 = (x, y, z - 1)
        spawnPos = []
        spawnPos.append(pos1)
        spawnPos.append(pos2)
        spawnPos.append(pos3)
        spawnPos.append(pos4)
        for i in range(4):
            x = spawnPos[i][0]
            z = spawnPos[i][2]
            y = spawnPos[i][1]
            here = this.tDic.get('x'+str(x)+'y'+str(y)+'z'+str(z))
            below = this.tDic.get('x'+str(x)+'y'+str(y-1)+'z'+str(z))
            # 判断两次，这覆盖了这些位置：潜在洞穴和下面的潜在洞穴墙壁的间隙和地形
            if here == None and (below == 's' or below == None):
                e = Entity(model=this.cubeModel, texture=this.buildTex)
                # 缩小方块与普通地形大小匹配
                e.scale *= 0.99999
                # 生成位置围绕在mined之下
                e.position = spawnPos[i]
                this.adjustShadeAndRotation(e)
                # 父类生成立方体去构建实体
                e.parent = this.builds
                # 记录在字典中新生成的块
                this.tDic['x' + str(x) + 'y' + str(y) + 'z' + str(z)] = 's'


    #在bte的位置放置块
    def build(this):
        if this.buildMode == -1: return

        whatsHere = this.tDic.get('x' + str(this.bte.x) +
                                  'y' + str(this.bte.y) +
                                  'z' + str(this.bte.z))
        #Is so,return.No buildy.
        if whatsHere != 'gap' and whatsHere != None:
            return

        # 创建方块的参数属性
        #e = duplicate(bte)
        e=Entity(model=this.cubeModel,
                 position=this.bte.position)
        #e.collider = 'box'
        #e.texture = this.stoneTex
        e.texture = this.buildTex
        e.scale*=0.99999

        #测试使用的颜色
        #e.color=this.blockTypes[4]
        e.color = this.blockTypes[this.blockType]
        e.parent=this.builds
        # 记录在字典中新生成的块
        this.tDic['x' + str(e.x) + 'y' + str(e.y) + 'z' + str(e.z)] = 'b'
        this.builds.combine()
        #消除块的震荡不会生效（注释掉了e.shake）
        #e.shake(duration=0.5, speed=0.01)

    def mine(this):
        # 真正的地形挖掘
        vChange = False
        totalV = 0
        for v in this.builds.model.vertices:
            # 顶点是否足够接近我们要挖掘的位置
            if (v[0] >= this.bte.x - 0.5 and
                    v[0] <= this.bte.x + 0.5 and
                    v[1] >= this.bte.y - 0.5 and
                    v[1] <= this.bte.y + 0.5 and
                    v[2] >= this.bte.z - 0.5 and
                    v[2] <= this.bte.z + 0.5):
                # 移动顶点到高空9999，给人一种破坏物体的感觉
                v[1] = 9999
                vChange = True
                totalV +=1
                if totalV >= 36:break


        if vChange == True:

            whatsHere = this.tDic.get('x' + str(this.bte.x) +
                                      'y' + str(this.bte.y) +
                                      'z' + str(this.bte.z))

            # 在字典上记录新的缺口
            this.tDic['x' + str(this.bte.x) +
                      'y' + str(this.bte.y) +
                      'z' + str(this.bte.z)] = 'gap'

            if whatsHere !='b':
                this.mineSpawn()
                this.builds.combine()
            #更新顶点
            this.builds.model.generate()
            return
        #遍历我们所有的子集
        totalV= 0
        for s in range(len(this.subsets)):
            vChange = False
            for v in this.subsets[s].model.vertices:
                #顶点是否足够接近我们要挖掘的位置
                if(v[0] >= this.bte.x - 0.5 and
                   v[0] <= this.bte.x + 0.5 and
                   v[1] >= this.bte.y - 0.5 and
                   v[1] <= this.bte.y + 0.5 and
                   v[2] >= this.bte.z - 0.5 and
                   v[2] <= this.bte.z + 0.5 ):
                    #YES!
                   #v[1] -= 1
                   #移动顶点到高空9999，给人一种破坏物体的感觉
                   v[1] = 9999
                   vChange = True
                   #计算破坏多少方块
                   totalV += 1
                   # 有问题，销毁了36个顶点，而不是8个
                   # print("tV=" + str(totalY))
                   if totalV == 36: break
            # 洞穴词典中高度变化的记录 :)

            if vChange == True:
                # 在字典上记录新的缺口
                this.tDic['x' + str(this.bte.x) +
                          'y' + str(this.bte.y) +
                          'z' + str(this.bte.z)] = 'gap'
                this.mineSpawn()
                this.subsets[s].model.generate()
                this.builds.combine()
                return



        # 遍历我们所有的子集
        totalV = 0
        for s in range(len(this.megasets)):
            vChange = False
            for v in this.megasets[s].model.vertices:
                # 顶点是否足够接近我们要挖掘的位置
                if (v[0] >= this.bte.x - 0.5 and
                        v[0] <= this.bte.x + 0.5 and
                        v[1] >= this.bte.y - 0.5 and
                        v[1] <= this.bte.y + 0.5 and
                        v[2] >= this.bte.z - 0.5 and
                        v[2] <= this.bte.z + 0.5):
                    # YES!
                    # v[1] -= 1
                    # 移动顶点到高空9999，给人一种破坏物体的感觉
                    v[1] = 9999
                    vChange = True
                    # 计算破坏多少方块
                    totalV += 1
                    # 有问题，销毁了36个顶点，而不是8个
                    # print("tV=" + str(totalY))
                    if totalV == 36: break
            # 洞穴词典中高度变化的记录 :)

            if vChange == True:
                # 在字典上记录新的缺口
                this.tDic['x' + str(this.bte.x) +
                          'y' + str(this.bte.y) +
                          'z' + str(this.bte.z)] = 'gap'
                this.mineSpawn()
                this.megasets[s].model.generate()
                this.builds.combine()
                return

